import 'package:family_expense/features/bank_card/models/bank_card.dart';
import 'package:family_expense/features/bank_card/services/bank_card_service.dart';
import 'package:family_expense/features/bank_card/widgets/bank_card_shared.dart';
import 'package:family_expense/features/bank_card/widgets/bank_shared.dart';
import 'package:family_expense/features/income_expense/constants/income_expense_type.dart';
import 'package:family_expense/features/income_expense/constants/payment_type.dart';
import 'package:family_expense/features/income_expense/models/income_expense_detail.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_shared.dart';
import 'package:family_expense/features/income_expense_search/widgets/income_expense_search_result.dart';
import 'package:flutter/material.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

class IncomeExpenseSearchHome extends StatefulWidget {
  const IncomeExpenseSearchHome({super.key});

  @override
  State<IncomeExpenseSearchHome> createState() =>
      _IncomeExpenseSearchHomeState();
}

class _IncomeExpenseSearchHomeState extends State<IncomeExpenseSearchHome> {
  final int _animationDurationInMillionsecond = 200;

  // For keyword input textfield.
  final TextEditingController _textEditingController = TextEditingController();

  // For display bank cards selection.
  final BankCardService _bankCardService = BankCardService();

  // The bank cards for selection.
  late final List<BankCard>? _bankCards = _bankCardService.currentBankCards;

  // The search arguments which will be passed to search result view.
  IncomeExpenseSearchArguments _searchArguments =
      IncomeExpenseSearchArguments();

  // Used to notify last view that item has been updated.
  bool _dataUpdated = false;

  // Recent search history list.
  List<String>? _recentSearchList;

  @override
  void initState() {
    super.initState();

    _loadRecentSearchHistoryList();
  }

  @override
  void dispose() {
    _textEditingController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvokedWithResult: _onPopInvokedWithResult,
      child: Scaffold(appBar: _buildAppBar(), body: _buildBody()),
    );
  }

  /// Builds app bar.
  PreferredSizeWidget _buildAppBar() {
    return AppBar(title: const Text('搜索'));
  }

  /// Builds main body.
  Widget _buildBody() {
    return ListView(
      padding: const EdgeInsets.all(4.0),
      children: [
        _buildSearchInput(),
        _buildRecentSearch(),
        const SizedBox(height: 10.0),
        _buildAdvancedOptions(),
      ],
    );
  }

  /// Builds input field for search.
  Widget _buildSearchInput() {
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: TextFormField(
        controller: _textEditingController,
        decoration: InputDecoration(
          hintText: '搜索详情/备注',
          prefixIcon: const Icon(Icons.search),
          suffixIcon: IconButton(
            icon: const Icon(Icons.check),
            onPressed: () async {
              _searchArguments.keyword = _textEditingController.text;

              // Saves non-empty keyword.
              // If puts this logic after NavigatorHelper.pushNamed then might not trigger this code.
              // For example, copy to a new item will be navigated back to home.
              if (_searchArguments.keyword.isNotNullOrEmpty && mounted) {
                setState(() {
                  _insertIntoRecentSearchHistoryList(_searchArguments.keyword!);
                  _saveRecentSearchHistoryList();
                });
              }

              final dataUpdated = await NavigatorHelper.push<bool>(
                context,
                IncomeExpenseSearchResult(searchArguments: _searchArguments),
              );

              if (dataUpdated == true) {
                // We only need to set [_dataUpdated] as true when [dataUpdated] is true.
                //
                // - When user chaged one item then [dataUpdated] is true and [_dataUpdated] is true.
                // - When user goes to edit view and gets back without any change, then [dataUpdated] is false.
                // But we still need to notify last page that some items have been changed.
                //
                // That's why we cannnot set [_dataUpdated] to false when [dataUpdated] is false.
                _dataUpdated = true;
              }
            },
          ),
        ),
      ),
    );
  }

  /// Builds recent search history.
  Widget _buildRecentSearch() {
    return Padding(
      padding: const EdgeInsets.all(6.0),
      child: Wrap(
        spacing: 4.0,
        runSpacing: -10.0,
        children:
            _recentSearchList
                ?.map(
                  (e) => InputChip(
                    label: Text(
                      e,
                      style: Theme.of(context).textTheme.bodySmall,
                    ),
                    deleteIcon: const Icon(Icons.clear, size: 16.0),
                    onDeleted: () {
                      if (mounted) {
                        setState(() {
                          _removeFromRecentSearchHistoryList(e);
                          _saveRecentSearchHistoryList();
                        });
                      }
                    },
                    deleteButtonTooltipMessage: '删除',
                    onPressed: () => _textEditingController.text = e,
                  ),
                )
                .toList() ??
            [],
      ),
    );
  }

  /// Builds advanced search options.
  Widget _buildAdvancedOptions() {
    return ExpansionTile(
      title: const Text('高级'),
      children: [
        SimpleDetailListTile(
          title: const Text('开始日期'),
          value: Text(
            _searchArguments.startDate != null
                ? _searchArguments.startDate.formatDate(DatePatterns.longDate)
                : '',
          ),
          onTap: () async {
            final selectedDate = await showMyDatePicker(
              context,
              initialDate: _searchArguments.startDate,
              lastDate: _searchArguments.endDate,
            );

            if (selectedDate != null && mounted) {
              setState(() => _searchArguments.startDate = selectedDate);
            }
          },
        ),
        SimpleDetailListTile(
          title: const Text('结束日期'),
          value: Text(
            _searchArguments.endDate != null
                ? _searchArguments.endDate.formatDate(DatePatterns.longDate)
                : '',
          ),
          onTap: () async {
            final selectedDate = await showMyDatePicker(
              context,
              initialDate: _searchArguments.endDate,
              firstDate: _searchArguments.startDate,
            );

            if (selectedDate != null && mounted) {
              setState(() => _searchArguments.endDate = selectedDate);
            }
          },
        ),
        const Divider(),
        SimpleDetailListTile(
          title: const Text('支出/收入'),
          value: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              _searchArguments.type != null
                  ? IncomeExpenseDetailShared.getTypeIcon(
                      _searchArguments.type,
                    )!
                  : Container(),
              const SizedBox(width: 10.0),
              Text(
                IncomeExpenseType.getCategories()[_searchArguments.type] ?? '',
              ),
            ],
          ),
          onTap: () => _showIncomeExpenseTypeModalBottomSheet(),
        ),
        AnimatedSize(
          duration: Duration(milliseconds: _animationDurationInMillionsecond),
          child: Visibility(
            visible: _searchArguments.type != null,
            child: SimpleDetailListTile(
              title: const Text('收支类别'),
              value: Text(
                IncomeExpenseDetailShared.getIncomeOrExpenseTypeTitle(
                  IncomeExpenseDetail(
                    type: _searchArguments.type,
                    detailType: _searchArguments.detailType,
                  ),
                ),
              ),
              onTap: () => _searchArguments.type == IncomeExpenseType.income
                  ? _showIncomeTypeModalBottomSheet()
                  : _showExpenseTypeModalBottomSheet(),
            ),
          ),
        ),
        SimpleDetailListTile(
          title: const Text('收支方式'),
          value: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              IncomeExpenseDetailShared.getTypeIcon(
                    _searchArguments.paymentType,
                  ) ??
                  Container(),
              const SizedBox(width: 10.0),
              Text(
                PaymentType.getCategories()[_searchArguments.paymentType] ?? '',
              ),
            ],
          ),
          onTap: () {
            _showPaymentTypeModalBottomSheet();
          },
        ),
        AnimatedSize(
          duration: Duration(milliseconds: _animationDurationInMillionsecond),
          child: Visibility(
            visible: _searchArguments.paymentType != null,
            child: SimpleDetailListTile(
              title: const Text('选择卡片'),
              value: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  _searchArguments.bankCard?.id != null
                      ? BankLogo(_searchArguments.bankCard!.bank!)
                      : Container(),
                  const SizedBox(width: 10.0),
                  Text(_searchArguments.bankCard?.name ?? ''),
                ],
              ),
              onTap: () {
                BankCardShared.showBankCardModalBottomSheet(
                  context,
                  BankCardShared.getRelatedBankCards(
                    _bankCards!,
                    _searchArguments.paymentType,
                  ),
                  (bankCard) {
                    if (mounted) {
                      // Triggers the build.
                      setState(() => _searchArguments.bankCard = bankCard);
                    }

                    // Pops the modal.
                    NavigatorHelper.pop(context);
                  },
                  title: '选择卡片',
                  bankCard: _searchArguments.bankCard,
                );
              },
            ),
          ),
        ),
        SimpleDetailListTile(
          title: const Text('详情/备注多关键字匹配'),
          value: Text(
            _getKeywordsSearchConditionText(
              _searchArguments.keywordsSearchCondition!,
            )!,
          ),
          onTap: _showSearchConditionSelectionModalBottomSheet,
        ),
        const SizedBox(height: 20.0),
        ListTile(
          title: const Text(
            '重置所有条件',
            textAlign: TextAlign.center,
            style: TextStyle(color: Colors.blue),
          ),
          onTap: () async {
            if (mounted) {
              setState(() => _searchArguments = IncomeExpenseSearchArguments());
            }
          },
        ),
      ],
    );
  }

  /// Shows a pick modal for income or expense selection.
  void _showIncomeExpenseTypeModalBottomSheet() {
    IncomeExpenseDetailShared.showIncomeExpenseTypeModalBottomSheet(context, (
      type,
    ) {
      if (mounted) {
        // Triggers build.
        setState(() {
          // When the type changes we need to reset previous data.
          _searchArguments.type = type;
          _searchArguments.detailType = null;
        });
      }

      // Closes modal.
      NavigatorHelper.pop(context);
    }, currentType: _searchArguments.type);
  }

  /// Shows a pick modal for income type selection.
  void _showIncomeTypeModalBottomSheet() {
    IncomeExpenseDetailShared.showIncomeDetailTypeModalBottomSheet(context, (
      type,
    ) {
      if (mounted) {
        // Triggers build.
        setState(() => _searchArguments.detailType = type);
      }

      // Closes modal.
      NavigatorHelper.pop(context);
    }, currentType: _searchArguments.detailType);
  }

  /// Shows a pick modal for expense type selection.
  void _showExpenseTypeModalBottomSheet() {
    IncomeExpenseDetailShared.showExpenseDetailTypeModalBottomSheet(context, (
      type,
    ) {
      if (mounted) {
        // Triggers build.
        setState(() => _searchArguments.detailType = type);
      }

      // Closes modal.
      NavigatorHelper.pop(context);
    }, currentType: _searchArguments.detailType);
  }

  /// Shows a pick modal for payment type selection.
  void _showPaymentTypeModalBottomSheet() {
    IncomeExpenseDetailShared.showPaymentTypeModalBottomSheet(context, (type) {
      if (mounted) {
        // Triggers build.
        setState(() {
          _searchArguments.paymentType = type;
          _searchArguments.bankCard = null;
        });
      }

      // Closes modal.
      NavigatorHelper.pop(context);
    }, currentType: _searchArguments.paymentType);
  }

  /// Show modal bottom sheet to select search condition if search based on multiple keywords.
  void _showSearchConditionSelectionModalBottomSheet() {
    showModalBottomSheet<void>(
      context: context,
      builder: (context) {
        return SizedBox(
          height: 210.0,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const SizedBox(height: 15.0),
              const Text('详情/备注多关键字匹配', style: TextStyle(fontSize: 18.0)),
              const SizedBox(height: 10.0),
              Expanded(
                child: ListView(
                  children: [
                    ListTile(
                      title: Text(
                        _getKeywordsSearchConditionText(
                          IncomeExpenseSearchArguments
                              .keywordsSearchOrCondition,
                        )!,
                      ),
                      subtitle: const Text('任何一个匹配即可满足'),
                      selected:
                          _searchArguments.keywordsSearchCondition ==
                          IncomeExpenseSearchArguments
                              .keywordsSearchOrCondition,
                      onTap: () {
                        if (mounted) {
                          setState(() {
                            _searchArguments.keywordsSearchCondition =
                                IncomeExpenseSearchArguments
                                    .keywordsSearchOrCondition;
                          });

                          // Closes modal.
                          NavigatorHelper.pop(context);
                        }
                      },
                    ),
                    ListTile(
                      title: Text(
                        _getKeywordsSearchConditionText(
                          IncomeExpenseSearchArguments
                              .keywordsSearchAndCondition,
                        )!,
                      ),
                      subtitle: const Text('必须同时匹配才可满足'),
                      selected:
                          _searchArguments.keywordsSearchCondition ==
                          IncomeExpenseSearchArguments
                              .keywordsSearchAndCondition,
                      onTap: () {
                        if (mounted) {
                          setState(() {
                            _searchArguments.keywordsSearchCondition =
                                IncomeExpenseSearchArguments
                                    .keywordsSearchAndCondition;
                          });

                          // Closes modal.
                          NavigatorHelper.pop(context);
                        }
                      },
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  /// Gets the text for different search condition.
  String? _getKeywordsSearchConditionText(String condition) {
    final conditionSet = {
      IncomeExpenseSearchArguments.keywordsSearchOrCondition: '或',
      IncomeExpenseSearchArguments.keywordsSearchAndCondition: '与',
    };

    return conditionSet[condition];
  }

  /// Inserts keyword into loaded recent search history list's first position.
  void _insertIntoRecentSearchHistoryList(String keyword) {
    keyword = keyword.trim();

    // Removes and inserts again just makes sure this keyword is in the first position.
    _removeFromRecentSearchHistoryList(_searchArguments.keyword!);

    // If list length reaches max count then we need to remove the last one.
    if (_recentSearchList!.length == GeneralConfig.recentSearchListMaxCount) {
      _recentSearchList!.removeAt(GeneralConfig.recentSearchListMaxCount! - 1);
    }

    _recentSearchList!.insert(0, keyword);
  }

  /// Removes keyword from loaded recent search history list.
  void _removeFromRecentSearchHistoryList(String keyword) {
    keyword = keyword.trim();

    if (_recentSearchList!.contains(keyword)) {
      _recentSearchList!.remove(keyword);
    }
  }

  /// Loads saved recent search history list from local storage.
  Future<void> _loadRecentSearchHistoryList() async {
    List<String> list = [];

    // Loads saved recent search.
    final savedRecentSearch = await LocalStorage.get<String>(
      GeneralConfig.localRecentSearchStorageKey,
    );

    // Builds string list if it is not null or empty.
    if (savedRecentSearch.isNotNullOrEmpty) {
      list = savedRecentSearch!.split(GeneralConfig.stringToListSeparator);
    }

    if (mounted) {
      setState(() => _recentSearchList = list);
    }
  }

  /// Saves recent search history list to local storage.
  Future<void> _saveRecentSearchHistoryList() async {
    LocalStorage.set<String>(
      GeneralConfig.localRecentSearchStorageKey,
      _recentSearchList!.join(GeneralConfig.stringToListSeparator),
    );
  }

  void _onPopInvokedWithResult(bool didPop, dynamic result) {
    if (didPop) {
      return;
    }

    NavigatorHelper.pop(context, _dataUpdated);
  }
}
